package cn.dakaqi.exceptionhandler;

import cn.dakaqi.enumerate.CommonStatusCode;
import cn.dakaqi.exception.EncryptionException;
import cn.dakaqi.exception.LoginRequiredException;
import cn.dakaqi.exception.MaibaoParamException;
import cn.dakaqi.utils.exception.ServiceRuntimeException;
import cn.dakaqi.vo.response.BaseResponseVo;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;


/**
 * @author Jay
 *         <p>
 *         Handle different kinds of exceptions being thrown from controllers
 *         <p>
 *         Transalate those exceptions into well formatted json string
 */
@ControllerAdvice
public class RestErrorHandler {

    @Resource
    private MessageSource messageSource;

    @Autowired
    public RestErrorHandler(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public ResponseEntity<BaseResponseVo> processHttpMessageNotReadable() {
        return new ResponseEntity<>(
                new BaseResponseVo(-1, "服务器出问题了"), HttpStatus.OK);
    }

    @ExceptionHandler(ServiceRuntimeException.class)
    @ResponseBody
    public BaseResponseVo processServiceRuntimeException(ServiceRuntimeException e) {
        return new BaseResponseVo(CommonStatusCode.SERVER_EXCEPTION.getStatusCode(), e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public BaseResponseVo processException(Exception e) {
        return new BaseResponseVo(CommonStatusCode.SERVER_EXCEPTION.getStatusCode(),e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseEntity<BaseResponseVo> processMethodArgumentNotValid(MethodArgumentNotValidException e) {
        return new ResponseEntity<>(new BaseResponseVo(-1, message(e.getBindingResult())),
                HttpStatus.OK);
    }

    @ExceptionHandler(LoginRequiredException.class)
    @ResponseBody
    public BaseResponseVo processLoginRequired() {
        return new BaseResponseVo(CommonStatusCode.COMMON_USER_NOT_LOGIN.getStatusCode(), CommonStatusCode.COMMON_USER_NOT_LOGIN.getStatusMessage());
    }

    @ExceptionHandler(EncryptionException.class)
    @ResponseBody
    public ResponseEntity<BaseResponseVo> processEncryption(EncryptionException e) {
        e.getField();//错误字段
        e.getErrorCode();//错误代码
        return new ResponseEntity<>(new BaseResponseVo(CommonStatusCode.COMMON_INVALID_SIGN.getStatusCode(), CommonStatusCode.COMMON_INVALID_SIGN.getStatusMessage()),
                HttpStatus.OK);
    }

    //脉宝参数错误异常处理
    @ExceptionHandler(MaibaoParamException.class)
    @ResponseBody
    public ResponseEntity<BaseResponseVo> processLoginRequired(MaibaoParamException e) {
        return new ResponseEntity<>(new BaseResponseVo(1, e.getErrMsg()),
                HttpStatus.OK);
    }

    @ExceptionHandler(value = {IllegalArgumentException.class, IllegalStateException.class})
    @ResponseBody
    protected ResponseEntity<BaseResponseVo> handleConflict(RuntimeException e) {
        return new ResponseEntity<>(new BaseResponseVo(-1, message(e.getMessage())), HttpStatus.OK);
    }

    @ExceptionHandler(value = {DataIntegrityViolationException.class})
    @ResponseBody
    protected ResponseEntity<BaseResponseVo> handleConflict(DataIntegrityViolationException e) {
        if (e.getCause() instanceof ConstraintViolationException) {
            ConstraintViolationException ex = (ConstraintViolationException) e.getCause();
            if (ex.getCause() instanceof SQLException) {
                SQLException exx = (SQLException) ex.getCause();
                return new ResponseEntity<>(new BaseResponseVo(-1, exx.getMessage()), HttpStatus.OK);
            }
            return new ResponseEntity<>(new BaseResponseVo(-1, ex.getMessage()), HttpStatus.OK);
        }
        return new ResponseEntity<>(new BaseResponseVo(-1, e.getMessage()), HttpStatus.OK);
    }

    private String message(String code) {
        return messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
    }

    private String message(BindingResult result) {
        StringBuilder sb = new StringBuilder();
        List<FieldError> fieldErrors = result.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            sb.append(messageSource.getMessage(fieldError, LocaleContextHolder.getLocale()));
        }
        return sb.toString();
    }

}